package gnss

import (
	"bytes"
	"dgo/goutils/utils"
	"strings"
)

var (
	Vrs_Unicorelist = []byte{SYS_GPS, SYS_GLO, SYS_GAL, SYS_QZS, SYS_BD}
	// 2I(02) 1X(07) 6I(08) 7I(14) 5X(19)
	Msm7_Unicore_BdsFixed = []byte{RTCM_SIG_BDS_B1_2I, 7, RTCM_BDS_SIGN_B3_6I, RTCM_SIG_BDS_B2_7I, 19}
	Vrs_QXlist            = []byte{SYS_GLO, SYS_BD, SYS_GPS, SYS_GAL, SYS_QZS}
	Vrs_QX_GloFixed       = []byte{RTCM_SIG_GLO_G1_1C, RTCM_SIG_GLO_G1_1P, RTCM_SIG_GLO_G2_2C, RTCM_SIG_GLO_G2_2P}

	Vrs_YDlist = []byte{SYS_GPS, SYS_GLO, SYS_GAL, SYS_QZS, SYS_BD}
)

// 针对vars的设定频点进行编码和系统(北斗根据BD3/BD2开关)
// 不支持fixed设定, navisys设定
// 忽略Header.EncodeType
func RtcmRawEpochEncodRtcmMsm4V2(src *RtcmRawObsEpoch, vars *EncodeVars, onRtcmHead func(head *RtcmRawMsmHeader), onRtcmBuf func(msgid uint16, buf []byte)) {

	nextfn := src.NextObs
	if len(src.SortList) > 0 {
		nextfn = src.NextObsBySortList
	}

	if vars == nil {
		return
	}

	naviSys := SYS_UNKOWN
	obs := nextfn(naviSys)

	naviSysBytes := []byte(vars.NaviSysFilter)

	msmlst := make([]*RtcmRawMsm4, 0, NAVI_SYS_MAX)
	var sigs []byte
	var all bool
	for obs != nil {
		// 下一次
		next := nextfn(obs.Header.NaviSys)

		if obs.Header.NaviSys == SYS_BD {
			if vars.BD2_enable {
				sigs = vars.BD2_SigWl
				all = len(sigs) == 0 && bytes.IndexByte(naviSysBytes, 'C') != -1
				EncodeMsm4FromObsV2(obs, func(satid uint16, sigid byte) bool {
					return satid <= 16 && (all || bytes.IndexByte(sigs, sigid) != -1)
				}, func() *RtcmRawMsm4 {
					msm4 := NewRtcmRawMsm4()
					obs.Header.WriteInfo2MsmHeader(&msm4.Header)
					msm4.Header.MsgID = GetMsm4MsgIDByNaviSys(msm4.Header.NaviSys)
					msm4.Header.SetTOW(src.TOW)
					if onRtcmHead != nil {
						onRtcmHead(&msm4.Header)
					}
					return msm4
				}, func(msm *RtcmRawMsm4) {
					if msm.Header.CellN > 0 {
						msmlst = append(msmlst, msm)
					}
				})
			}

			if vars.BD3_enable {
				sigs = vars.BD3_SigWl
				all = len(sigs) == 0 && bytes.IndexByte(naviSysBytes, 'C') != -1
				EncodeMsm4FromObsV2(obs, func(satid uint16, sigid byte) bool {
					return satid > 16 && (all || bytes.IndexByte(sigs, sigid) != -1)
				}, func() *RtcmRawMsm4 {
					msm4 := NewRtcmRawMsm4()
					obs.Header.WriteInfo2MsmHeader(&msm4.Header)
					msm4.Header.MsgID = GetMsm4MsgIDByNaviSys(msm4.Header.NaviSys)
					msm4.Header.SetTOW(src.TOW)
					if onRtcmHead != nil {
						onRtcmHead(&msm4.Header)
					}
					return msm4
				}, func(msm *RtcmRawMsm4) {
					if msm.Header.CellN > 0 {
						msmlst = append(msmlst, msm)
					}
				})
			}

			obs = next
			continue
		} else if obs.Header.NaviSys == SYS_GPS {
			sigs = vars.GPS_SigWl
			all = len(sigs) == 0 && bytes.IndexByte(naviSysBytes, 'G') != -1
		} else if obs.Header.NaviSys == SYS_GLO { // GLO
			sigs = vars.GLO_SigWl
			all = len(sigs) == 0 && bytes.IndexByte(naviSysBytes, 'R') != -1
		} else if obs.Header.NaviSys == SYS_GAL {
			sigs = vars.GAL_SigWl
			all = len(sigs) == 0 && bytes.IndexByte(naviSysBytes, 'E') != -1
		} else if obs.Header.NaviSys == SYS_QZS {
			sigs = vars.QZS_SigWl
			all = len(sigs) == 0 && bytes.IndexByte(naviSysBytes, 'J') != -1
		}
		// 没有信号也不是所有频点
		if len(sigs) == 0 && !all {
			obs = next
			continue
		}

		EncodeMsm4FromObsV2(obs, func(satid uint16, sigid byte) bool {
			return all || bytes.IndexByte(sigs, sigid) != -1
		}, func() *RtcmRawMsm4 {
			msm4 := NewRtcmRawMsm4()
			obs.Header.WriteInfo2MsmHeader(&msm4.Header)
			msm4.Header.MsgID = GetMsm4MsgIDByNaviSys(msm4.Header.NaviSys)
			msm4.Header.SetTOW(src.TOW)
			if onRtcmHead != nil {
				onRtcmHead(&msm4.Header)
			}
			return msm4
		}, func(msm *RtcmRawMsm4) {
			if msm.Header.CellN > 0 {
				msmlst = append(msmlst, msm)
			}
		})
		obs = next
	}

	n := len(msmlst)

	if n > 0 {
		// 最后一个
		var bb utils.BytesBuilder
		msmlst[n-1].Header.EpochEndFlag = true
		for i := 0; i < n; i++ {
			msm := msmlst[i]
			msm.EncodeMsm(&bb, 0)
			onRtcmBuf(msm.Header.MsgID, bb.Bytes())
			bb.Reset()
		}
	}
}

/*
RtcmRawObsEpoch 编码成RTCM Buf
不推荐直接使用， 调试用
*/
func RtcmRawEpochEncodRtcmMsm4_0(src *RtcmRawObsEpoch, vars *EncodeVars, chkEndMsm int, onRtcmHead func(head *RtcmRawMsmHeader), onRtcmBuf func(msgid uint16, buf []byte)) {

	// 先处理掉不要的数据
	src.RangeObs(func(obs *RtcmRawMsmObs) {
		if vars != nil && len(vars.NaviSysFilter) > 0 && !strings.Contains(vars.NaviSysFilter, GetNavSysCode(obs.Header.NaviSys)) {
			src.DelNaviSys(obs.Header.NaviSys)
			return
		}
	})

	nextfn := src.NextObs
	if len(src.SortList) > 0 {
		nextfn = src.NextObsBySortList
	}

	naviSys := SYS_UNKOWN
	obs := nextfn(naviSys)

	msmlst := make([]*RtcmRawMsm4, 0, NAVI_SYS_MAX)
	var sigs []byte
	var fixsigs []byte
	for obs != nil {

		next := nextfn(obs.Header.NaviSys)
		if vars != nil {
			if obs.Header.NaviSys == SYS_BD {
				if !vars.BD3_enable {
					obs.DelSats(17, 0)
				}

				if !vars.BD2_enable {
					obs.DelSats(0, 16)
				}

				if len(vars.BDS_DelPrns) > 0 {
					obs.DelSatsEx(vars.BDS_DelPrns...)
				}
				sigs = vars.BDS_SigWl
				fixsigs = vars.BDS_SigFixed
			} else if obs.Header.NaviSys == SYS_GPS {
				sigs = vars.GPS_SigWl
				fixsigs = nil
			} else if obs.Header.NaviSys == SYS_GLO { // GLO
				sigs = vars.GLO_SigWl
				fixsigs = vars.GLO_SigFixed
			} else if obs.Header.NaviSys == SYS_GAL {
				sigs = vars.GAL_SigWl
				fixsigs = nil
			} else if obs.Header.NaviSys == SYS_QZS {
				sigs = vars.QZS_SigWl
				fixsigs = nil
			}
		}

		EncodeMsm4FromObsV1(obs, sigs, fixsigs, func() *RtcmRawMsm4 {
			msm4 := NewRtcmRawMsm4()
			obs.Header.WriteInfo2MsmHeader(&msm4.Header)
			msm4.Header.MsgID = GetMsm4MsgIDByNaviSys(msm4.Header.NaviSys)
			msm4.Header.SetTOW(src.TOW)
			if onRtcmHead != nil {
				onRtcmHead(&msm4.Header)
			}
			return msm4
		}, func(msm *RtcmRawMsm4) {
			if msm.Header.CellN > 0 {
				msmlst = append(msmlst, msm)
			}
		})
		obs = next
	}

	n := len(msmlst)

	if n > 0 {
		// 最后一个
		var bb utils.BytesBuilder
		if chkEndMsm == 1 {
			msmlst[n-1].Header.EpochEndFlag = true
		}
		for i := 0; i < n; i++ {
			msm := msmlst[i]
			msm.EncodeMsm(&bb, 0)
			onRtcmBuf(msm.Header.MsgID, bb.Bytes())
			bb.Reset()
		}
	}
}

/*
RtcmRawObsEpoch 编码成RTCM Buf
*/
func RtcmRawEpochEncodRtcmMsm4(src *RtcmRawObsEpoch, vars *EncodeVars, onRtcmHead func(head *RtcmRawMsmHeader), onRtcmBuf func(msgid uint16, buf []byte)) {
	RtcmRawEpochEncodRtcmMsm4_0(src, vars, 1, onRtcmHead, onRtcmBuf)
}

/*
*

	RtcmRawObsEpoch 编码成RTCM Buf
*/
func RtcmRawEpochEncodRtcmMsm7(src *RtcmRawObsEpoch, vars *EncodeVars, onRtcmHead func(head *RtcmRawMsmHeader), onRtcmBuf func(msgid uint16, buf []byte)) {

	// 先处理掉不要的数据
	src.RangeObs(func(obs *RtcmRawMsmObs) {
		if len(vars.NaviSysFilter) > 0 && !strings.Contains(vars.NaviSysFilter, GetNavSysCode(obs.Header.NaviSys)) {
			src.DelNaviSys(obs.Header.NaviSys)
			return
		}
	})

	nextfn := src.NextObs
	if len(src.SortList) > 0 {
		nextfn = src.NextObsBySortList
	}

	naviSys := SYS_UNKOWN
	obs := nextfn(naviSys)

	msmlst := make([]*RtcmRawMsm7, 0, NAVI_SYS_MAX)
	var sigs []byte
	var fixsigs []byte
	for obs != nil {

		next := nextfn(obs.Header.NaviSys)
		if obs.Header.NaviSys == SYS_BD {
			if !vars.BD3_enable {
				obs.DelSats(17, 0)
			}

			if len(vars.BDS_DelPrns) > 0 {
				obs.DelSatsEx(vars.BDS_DelPrns...)
			}
			sigs = vars.BDS_SigWl
			fixsigs = vars.BDS_SigFixed
		} else if obs.Header.NaviSys == SYS_GPS {
			sigs = vars.GPS_SigWl
			fixsigs = nil
		} else if obs.Header.NaviSys == SYS_GLO { // GLO
			sigs = vars.GLO_SigWl
			fixsigs = vars.GLO_SigFixed
		} else if obs.Header.NaviSys == SYS_GAL {
			sigs = vars.GAL_SigWl
			fixsigs = nil
		} else if obs.Header.NaviSys == SYS_QZS {
			sigs = vars.QZS_SigWl
			fixsigs = nil
		}

		EncodeMsm7FromObs(obs, sigs, fixsigs, func() *RtcmRawMsm7 {
			msm := NewRtcmRawMsm7()
			obs.Header.WriteInfo2MsmHeader(&msm.Header)
			msm.Header.MsgID = GetMsm7MsgIDByNaviSys(msm.Header.NaviSys)
			msm.Header.SetTOW(src.TOW)
			if onRtcmHead != nil {
				onRtcmHead(&msm.Header)
			}
			return msm
		}, func(msm *RtcmRawMsm7) {
			if msm.Header.CellN > 0 {
				msmlst = append(msmlst, msm)
			}
		})
		obs = next
	}

	n := len(msmlst)
	if n == 0 {
		return
	}

	// 最后一个
	var bb utils.BytesBuilder
	msmlst[n-1].Header.EpochEndFlag = true
	for i := 0; i < n; i++ {
		msm := msmlst[i]
		msm.EncodeMsm(&bb, 0)
		onRtcmBuf(msm.Header.MsgID, bb.Bytes())
		bb.Reset()
	}
}
